﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using DiagramDesigner.Controls;
using System.Collections;
using System.Collections.ObjectModel;

namespace DiagramDesigner
{
    //These attributes identify the types of the named parts that are used for templating
    [TemplatePart(Name = "PART_DragThumb", Type = typeof(DragThumb))]
    [TemplatePart(Name = "PART_ResizeDecorator", Type = typeof(Control))]
    [TemplatePart(Name = "PART_ConnectorDecorator", Type = typeof(Control))]
    [TemplatePart(Name = "PART_Appearance", Type = typeof(Control))]
    [TemplatePart(Name = "PART_ContentPresenter", Type = typeof(ContentPresenter))]
    public partial class DesignerItem : ContentControl, ISelectable, IGroupable
    {
        #region ContentString
        
        private String _contentString;
        public String ContentString
        {
            get { return _contentString; }
            set { _contentString = value; }
        }
        public static readonly DependencyProperty ContentStringProperty = DependencyProperty.Register("ContentString", typeof(String), typeof(DesignerItem));
        
        #endregion

        #region ELEMENT TYPE

        private String _elementType;
        public String elementType
        {
            get { return _elementType; }
            set { _elementType = value; }
        }
        public static readonly DependencyProperty ElementTypeProperty = DependencyProperty.Register("ElementType", typeof(String), typeof(DesignerItem));
        
        #endregion

        #region ELEMENT VALUE

        private String _elementValue;
        public String elementValue
        {
            get { return _elementValue; }
            set { _elementValue = value; }
        }
        public static readonly DependencyProperty ElementValueProperty = DependencyProperty.Register("ElementValue", typeof(String), typeof(DesignerItem));

        #endregion

        #region ID
        private Guid id;
        public Guid ID
        {
            get { return id; }
        }
        #endregion

        #region ParentID
        public Guid ParentID
        {
            get { return (Guid)GetValue(ParentIDProperty); }
            set { SetValue(ParentIDProperty, value); }
        }
        public static readonly DependencyProperty ParentIDProperty = DependencyProperty.Register("ParentID", typeof(Guid), typeof(DesignerItem));
        #endregion

        #region IsGroup
        public bool IsGroup
        {
            get { return (bool)GetValue(IsGroupProperty); }
            set { SetValue(IsGroupProperty, value); }
        }
        public static readonly DependencyProperty IsGroupProperty =
            DependencyProperty.Register("IsGroup", typeof(bool), typeof(DesignerItem));
        #endregion

        #region IsSelected Property

        public bool IsSelected
        {
            get { return (bool)GetValue(IsSelectedProperty); }
            set { SetValue(IsSelectedProperty, value); }
        }
        public static readonly DependencyProperty IsSelectedProperty =
          DependencyProperty.Register("IsSelected",
                                       typeof(bool),
                                       typeof(DesignerItem),
                                       new FrameworkPropertyMetadata(false));

        #endregion

        #region AppearanceTemplate Property

        public static readonly DependencyProperty AppearanceTemplateProperty =
            DependencyProperty.RegisterAttached("AppearanceTemplate", typeof(ControlTemplate), typeof(DesignerItem));

        public static ControlTemplate AppearanceTemplate(UIElement element)
        {
            return (ControlTemplate)element.GetValue(AppearanceTemplateProperty);
        }

        public static void SetAppearanceTemplate(UIElement element, ControlTemplate value)
        {
            element.SetValue(AppearanceTemplateProperty, value);
        }

        #endregion

        #region DragThumbTemplate Property

        // can be used to replace the default template for the DragThumb
        public static readonly DependencyProperty DragThumbTemplateProperty =
            DependencyProperty.RegisterAttached("DragThumbTemplate", typeof(ControlTemplate), typeof(DesignerItem));

        public static ControlTemplate GetDragThumbTemplate(UIElement element)
        {
            return (ControlTemplate)element.GetValue(DragThumbTemplateProperty);
        }

        public static void SetDragThumbTemplate(UIElement element, ControlTemplate value)
        {
            element.SetValue(DragThumbTemplateProperty, value);
        }

        #endregion

        #region ConnectorDecoratorTemplate Property

        // can be used to replace the default template for the ConnectorDecorator
        public static readonly DependencyProperty ConnectorDecoratorTemplateProperty =
            DependencyProperty.RegisterAttached("ConnectorDecoratorTemplate", typeof(ControlTemplate), typeof(DesignerItem));

        public static ControlTemplate GetConnectorDecoratorTemplate(UIElement element)
        {
            return (ControlTemplate)element.GetValue(ConnectorDecoratorTemplateProperty);
        }

        public static void SetConnectorDecoratorTemplate(UIElement element, ControlTemplate value)
        {
            element.SetValue(ConnectorDecoratorTemplateProperty, value);
        }

        #endregion

        #region IsDragConnectionOver

        // while drag connection procedure is ongoing and the mouse moves over 
        // this item this value is true; if true the ConnectorDecorator is triggered
        // to be visible, see template
        public bool IsDragConnectionOver
        {
            get { return (bool)GetValue(IsDragConnectionOverProperty); }
            set { SetValue(IsDragConnectionOverProperty, value); }
        }
        public static readonly DependencyProperty IsDragConnectionOverProperty =
            DependencyProperty.Register("IsDragConnectionOver",
                                         typeof(bool),
                                         typeof(DesignerItem),
                                         new FrameworkPropertyMetadata(false));

        #endregion

        static DesignerItem()
        {
            // set the key to reference the style for this control
            FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(
                typeof(DesignerItem), new FrameworkPropertyMetadata(typeof(DesignerItem)));            
        }

        public DesignerItem(Guid id)
        {
            this.id = id;
            this.Loaded += new RoutedEventHandler(DesignerItem_Loaded);
        }

        public DesignerItem()
            : this(Guid.NewGuid())
        {
            // set default connectorDecoratorTemplate
            //this.Style = FindResource("DesignerItemDefaultStyle") as Style;
            SetConnectorDecoratorTemplate(this, FindResource("ConnectorDecoratorDefaultTemplate") as ControlTemplate);
            this.ApplyTemplate();
        }

        public DesignerItem(ControlTemplate appearanceTemplate, ControlTemplate connectorDecoratorTemplate)
            : this(Guid.NewGuid())
        {
            //this.Style = FindResource("DesignerItemDefaultStyle") as Style;
            SetAppearanceTemplate(this, appearanceTemplate);
            SetConnectorDecoratorTemplate(this, connectorDecoratorTemplate);
            this.ApplyTemplate();
        }
        
        protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
        {
            base.OnPreviewMouseDown(e);
            DesignerCanvas designer = VisualTreeHelper.GetParent(this) as DesignerCanvas;

            // update selection
            if (designer != null)
            {
                if ((Keyboard.Modifiers & (ModifierKeys.Shift | ModifierKeys.Control)) != ModifierKeys.None)
                    if (this.IsSelected)
                    {
                        designer.selectionService.RemoveFromSelection(this);
                    }
                    else
                    {
                        designer.selectionService.AddToSelection(this);
                    }
                else if (!this.IsSelected)
                {
                    designer.selectionService.SelectItem(this);
                }
                Focus();
            }

            e.Handled = false;
        }

        void DesignerItem_Loaded(object sender, RoutedEventArgs e)
        {
            if (base.Template != null)
            {
                ContentPresenter contentPresenter =
                    this.Template.FindName("PART_ContentPresenter", this) as ContentPresenter;
                if (contentPresenter != null)
                {
                    UIElement contentVisual = VisualTreeHelper.GetChild(contentPresenter, 0) as UIElement;
                    if (contentVisual != null)
                    {
                        DragThumb thumb = this.Template.FindName("PART_DragThumb", this) as DragThumb;
                        if (thumb != null)
                        {
                            ControlTemplate template =
                                DesignerItem.GetDragThumbTemplate(contentVisual) as ControlTemplate;
                            if (template != null)
                                thumb.Template = template;
                        }
                    }
                }
            }
        }

    }

    public class Properties
        {
            public string Name { get; set; }
            public string Value { get; set; }
        }

    public class DesignerItemContent : ContentControl
    {
        #region ID
        private Guid id;
        public Guid ID
        {
            get { return id; }
        }
        #endregion

        #region ElementTypeProperty

        public static readonly DependencyProperty ElementTypeProperty =
            DependencyProperty.RegisterAttached("ElementType", typeof(String), typeof(DesignerItemContent));

        public static String GetElementType(UIElement element)
        {
            return (String)element.GetValue(ElementTypeProperty);
        }

        public static void SetElementType(UIElement element, String value)
        {
            element.SetValue(ElementTypeProperty, value);
        }

        #endregion

        #region ElementValueProperty

        public static readonly DependencyProperty ElementValueProperty =
            DependencyProperty.RegisterAttached("ElementValue", typeof(String), typeof(DesignerItemContent));

        public String ElementValue
        {
            get { return (String)base.GetValue(ElementValueProperty); }
            set { base.SetValue(ElementValueProperty, value); }
        }

        public static String GetElementValue(UIElement element)
        {
            return (String)element.GetValue(ElementValueProperty);
        }

        public static void SetElementValue(UIElement element, String value)
        {
            element.SetValue(ElementValueProperty, value);
        }

        #endregion

        #region ContentPropertiesProperty

        public static readonly DependencyProperty ContentPropertiesProperty =
            DependencyProperty.RegisterAttached("ContentProperties", typeof(ObservableCollection<Properties>), typeof(DesignerItemContent));

        public static ObservableCollection<Properties> GetContentProperties(UIElement element)
        {
            return (ObservableCollection<Properties>)element.GetValue(ContentPropertiesProperty);
        }

        public static void SetContentProperties(UIElement element, ObservableCollection<Properties> value)
        {
            element.SetValue(ContentPropertiesProperty, value);
        }

        #endregion

        public void Set_PART_ElementValue_Template(ControlTemplate template, bool IsHitTestVisible)
        {
            this.ApplyTemplate();
            Control PART_ElementValue = this.Template.FindName("PART_ElementValue", this) as Control;
            PART_ElementValue.Template = template;
            PART_ElementValue.IsHitTestVisible = IsHitTestVisible;
        }
        
        static DesignerItemContent()
        {
            // set the key to reference the style for this control
            FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(
                typeof(DesignerItemContent), new FrameworkPropertyMetadata(typeof(DesignerItemContent)));
        }

        public DesignerItemContent(Guid id)
        {
            this.id = id;
        }

        public DesignerItemContent()
            : this(Guid.NewGuid())
        {
            this.Style = FindResource("DesignerItemContentDefaultStyle") as Style;
            this.ApplyTemplate();
            this.SetEventHandlers();
        }

        public DesignerItemContent(string contentTemplateName)
            : this(Guid.NewGuid())
        {
            this.Style = FindResource(contentTemplateName) as Style;
            this.ApplyTemplate();
            this.SetEventHandlers();
        }

        private void SetEventHandlers()
        {
            Control PART_ElementValue = this.Template.FindName("PART_ElementValue", this) as Control;
            PART_ElementValue.PreviewMouseDoubleClick += new MouseButtonEventHandler(PART_ElementValue_PreviewMouseDoubleClick);
            //PART_ElementValue.LostKeyboardFocus += new KeyboardFocusChangedEventHandler(PART_ElementValue_LostKeyboardFocus);
            PART_ElementValue.KeyUp += new KeyEventHandler(PART_ElementValue_KeyUp);
        }

        void PART_ElementValue_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            Control PART_ElementValue = this.Template.FindName("PART_ElementValue", this) as Control;
            Set_PART_ElementValue_Template(FindResource("ElementValueControlEdit") as ControlTemplate, true);
         }

        private DesignerItem _parentDI = null;
        public DesignerItem parentDI
        {
            get
            {
                if (_parentDI == null)
                {
                    DependencyObject parent = VisualTreeHelper.GetParent(this);

                    while (parent.GetType() != typeof(DesignerItem))
                    {
                        parent = VisualTreeHelper.GetParent(parent);
                    }

                    _parentDI = (DesignerItem)parent;
                    return _parentDI;
                }
                else
                    return _parentDI;
            }
            set { _parentDI = value; }
        }

        void PART_ElementValue_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Return)
            {
                Set_PART_ElementValue_Template(FindResource("ElementValueControlRead") as ControlTemplate, true);
                // set focus to canvas, so this item is not highlighted
                //parentDI.Focus();  
            }
        }

        void PART_ElementValue_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
        {
            Set_PART_ElementValue_Template(FindResource("ElementValueControlRead") as ControlTemplate, true);
        }       
    }
}
